package tech.lq0.dreamaticvoyage.block.entity;

import net.minecraft.core.BlockPos;
import net.minecraft.core.Direction;
import net.minecraft.core.NonNullList;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.network.chat.Component;
import net.minecraft.world.Container;
import net.minecraft.world.ContainerHelper;
import net.minecraft.world.MenuProvider;
import net.minecraft.world.WorldlyContainer;
import net.minecraft.world.entity.player.Inventory;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.inventory.AbstractContainerMenu;
import net.minecraft.world.inventory.ContainerData;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.block.entity.BlockEntity;
import net.minecraft.world.level.block.state.BlockState;
import org.jetbrains.annotations.Nullable;
import tech.lq0.dreamaticvoyage.block.machine.fukamizutech.tier2.FukamizuBooster;
import tech.lq0.dreamaticvoyage.gui.menu.FukamizuBoosterMenu;
import tech.lq0.dreamaticvoyage.init.BlockEntityRegistry;

public class FukamizuBoosterBlockEntity extends BlockEntity implements WorldlyContainer, MenuProvider {

    protected static final int SLOT_INPUT = 0;

    public static final int MAX_DATA_COUNT = 1;
    public static final int MAX_PRESSURE = 1024;
    public static final int SINGLE_PRESSURE = 16;

    protected NonNullList<ItemStack> items = NonNullList.withSize(1, ItemStack.EMPTY);

    public int pressure;

    protected final ContainerData dataAccess = new ContainerData() {
        public int get(int pIndex) {
            return FukamizuBoosterBlockEntity.this.pressure;
        }

        public void set(int pIndex, int pValue) {
            if (pIndex == 0) {
                FukamizuBoosterBlockEntity.this.pressure = pValue;
            }
        }

        public int getCount() {
            return MAX_DATA_COUNT;
        }
    };

    public FukamizuBoosterBlockEntity(BlockPos pPos, BlockState pBlockState) {
        super(BlockEntityRegistry.FUKAMIZU_BOOSTER_BLOCK_ENTITY.get(), pPos, pBlockState);
    }

    public static void serverTick(Level pLevel, BlockPos pPos, BlockState pState, FukamizuBoosterBlockEntity blockEntity) {
        int pressure = blockEntity.getPressure();
        int sp = pState.getValue(FukamizuBooster.PRESSURE);

        if (pressure != blockEntity.calculatePressure()) {
            blockEntity.pressure = blockEntity.calculatePressure();
            blockEntity.setChanged();
            pLevel.updateNeighbourForOutputSignal(pPos, pState.getBlock());
        }
        if (sp != blockEntity.calculateStatePressure()) {
            pLevel.setBlockAndUpdate(pPos, pState.setValue(FukamizuBooster.PRESSURE, blockEntity.calculateStatePressure()));
            setChanged(pLevel, pPos, pState);
        }
    }

    public int calculatePressure() {
        var item = this.items.get(SLOT_INPUT);
        if (item.is(Items.ANVIL) || item.is(Items.CHIPPED_ANVIL) || item.is(Items.DAMAGED_ANVIL)) {
            return item.getCount() * SINGLE_PRESSURE;
        }
        return 0;
    }

    public int calculateStatePressure() {
        var item = this.items.get(SLOT_INPUT);
        if (item.is(Items.ANVIL) || item.is(Items.CHIPPED_ANVIL) || item.is(Items.DAMAGED_ANVIL)) {
            if (item.getCount() > 0 && item.getCount() <= 16) {
                return 1;
            } else if (item.getCount() <= 32) {
                return 2;
            } else {
                return 3;
            }
        }
        return 0;
    }

    @Override
    public void load(CompoundTag pTag) {
        super.load(pTag);

        this.items = NonNullList.withSize(this.getContainerSize(), ItemStack.EMPTY);
        ContainerHelper.loadAllItems(pTag, this.items);
        this.pressure = pTag.getInt("Pressure");
    }

    @Override
    protected void saveAdditional(CompoundTag pTag) {
        super.saveAdditional(pTag);

        ContainerHelper.saveAllItems(pTag, this.items);
        pTag.putInt("Pressure", this.pressure);
    }

    @Override
    public int[] getSlotsForFace(Direction pSide) {
        return new int[]{};
    }

    @Override
    public boolean canPlaceItemThroughFace(int pIndex, ItemStack pItemStack, @Nullable Direction pDirection) {
        return false;
    }

    @Override
    public boolean canPlaceItem(int pIndex, ItemStack pStack) {
        return false;
    }

    @Override
    public boolean canTakeItemThroughFace(int pIndex, ItemStack pStack, Direction pDirection) {
        return false;
    }

    @Override
    public int getContainerSize() {
        return this.items.size();
    }

    @Override
    public boolean isEmpty() {
        for (ItemStack itemstack : this.items) {
            if (!itemstack.isEmpty()) {
                return false;
            }
        }

        return true;
    }

    @Override
    public ItemStack getItem(int pSlot) {
        return this.items.get(pSlot);
    }

    @Override
    public ItemStack removeItem(int pSlot, int pAmount) {
        return ContainerHelper.removeItem(this.items, pSlot, pAmount);
    }

    @Override
    public ItemStack removeItemNoUpdate(int pSlot) {
        return ContainerHelper.takeItem(this.items, pSlot);
    }

    @Override
    public void setItem(int pSlot, ItemStack pStack) {
        ItemStack itemstack = this.items.get(pSlot);
        boolean flag = !pStack.isEmpty() && ItemStack.isSameItemSameTags(itemstack, pStack);
        this.items.set(pSlot, pStack);
        if (pStack.getCount() > this.getMaxStackSize()) {
            pStack.setCount(this.getMaxStackSize());
        }

        if (pSlot == 0 && !flag) {
            this.setChanged();
        }
    }

    @Override
    public boolean stillValid(Player pPlayer) {
        return Container.stillValidBlockEntity(this, pPlayer);
    }

    @Override
    public void clearContent() {
        this.items.clear();
    }

    @Override
    public Component getDisplayName() {
        return Component.translatable("container.dreamaticvoyage.fukamizu_booster");
    }

    @Nullable
    @Override
    public AbstractContainerMenu createMenu(int pContainerId, Inventory pPlayerInventory, Player pPlayer) {
        return new FukamizuBoosterMenu(pContainerId, pPlayerInventory, this, this.dataAccess);
    }

    public int getPressure() {
        return this.pressure;
    }
}
